//-----------------------------------------------------------------------------
// Name: TuningParser.cpp
// Author: Brad Smith
// Desc: A simple text parser for tuning file format
//-----------------------------------------------------------------------------

#include "TuningParser.h"

#include "Assert.h"

#include <fstream>

cTuningParser::cTuningParser()
{

}

cTuningParser::cTuningParser(const char* fileName)
{
   ParseFile(fileName);   
}


cTuningParser::~cTuningParser()
{

}

cTuningParser::eParseReturn cTuningParser::ParseFile(const char* fileName)
{
	mFileName = fileName;

	mFloatData.clear();
	mIntData.clear();
	mStringData.clear();
	mBoolData.clear();

	// check that a valid file name was specified
	if (fileName == NULL)
		return kParseNoFile;

   // open the file
	std::ifstream inFile(fileName);

	// check that the file was opened
	if (!inFile)
		return kParseNoFile;

	const int kBufferSize = 256;
	char buffer[kBufferSize];
	char varTypeName[kBufferSize];
	char varName[kBufferSize];

	if (inFile.is_open())
	{
		while(!inFile.eof())
		{
			inFile.getline(buffer, kBufferSize - 1);

			switch (buffer[0])
			{
			case '#':
				// This line is a comment, ignore it.
				break;
			case 'i':
			case 'I':
				// Parse the value as an integer
				{
					int tuningVal = -1;

					if (sscanf_s(buffer, "%s %s %d", varTypeName, sizeof(varTypeName), varName, sizeof(varName), &tuningVal) == 3)
					{
						mIntData[varName] = tuningVal;
					}
				}
				break;
			case 'f':
			case 'F':
				// Parse the value as an float
				{
					float tuningVal = -1.0f;

					if (sscanf_s(buffer, "%s %s %f", varTypeName, sizeof(varTypeName), varName, sizeof(varName), &tuningVal) == 3)
					{
						mFloatData[varName] = tuningVal;
					}
				}
				break;
			case 'b':
			case 'B':
				// Parse the value as a bool
				{
					bool tuningVal = false;
					char tuningValAsString[kBufferSize];

					if (sscanf_s(buffer, "%s %s %s", varTypeName, sizeof(varTypeName), varName, sizeof(varName), tuningValAsString, sizeof(tuningValAsString)) == 3)
					{
						// naive check for false or true
						if (tuningValAsString[0] == 'f' || tuningValAsString[0] == 'F')
						{
							mBoolData[varName] = false;
						}
						else if (tuningValAsString[0] == 't' || tuningValAsString[0] == 'T')
						{
							mBoolData[varName] = true;
						}
						else
						{
							return kParseSyntaxError;
						}
					}
				}
				break;
			case 's':
			case 'S':
				// Parse the value as a string
				{
					if (sscanf_s(buffer, "%s %s", varTypeName, sizeof(varTypeName), varName, sizeof(varName)) == 2)
					{
						// find the first quotation mark
						int stringStartPosition = -1;
						for (int i = 0; i < kBufferSize; ++i)
						{
							// if we have found the leading quotation mark then note it's position
							if (buffer[i] == '"') 
							{
								if (stringStartPosition == -1)
								{
									stringStartPosition = i + 1;
								}
								else
								{
									// we're at the end quotation, so mark it as null and exit
									buffer[i] = '\0';
								}
							}
						}

						if (stringStartPosition == -1)
						{
							return kParseSyntaxError;
						}
						mStringData[varName] = &buffer[stringStartPosition];
					}
				}
				break;
			default:
				// ignore other lines
				break;
			}
		}
	}

	inFile.close();

	return kParseSuccess;
}

cTuningParser::eParseReturn cTuningParser::ReparseFile()
{
	return ParseFile(mFileName.c_str());
}

bool cTuningParser::GetTuningFloat(const char* tuningName, float& tuningVal)
{
   if (mFloatData.find(tuningName) != mFloatData.end())
   {
      tuningVal = mFloatData[tuningName];
      return true;
   }

   return false;
}

bool cTuningParser::GetTuningInt(const char* tuningName, int& tuningVal)
{
   if (mIntData.find(tuningName) != mIntData.end())
   {
      tuningVal = mIntData[tuningName];
      return true;
   }

   return false;
}

bool cTuningParser::GetTuningString(const char* tuningName, std::string& tuningVal)
{
	if (mStringData.find(tuningName) != mStringData.end())
	{
		tuningVal = mStringData[tuningName];
		return true;
	}

	return false;
}

bool cTuningParser::GetTuningBool(const char* tuningName, bool& tuningVal)
{
	if (mBoolData.find(tuningName) != mBoolData.end())
	{
		tuningVal = mBoolData[tuningName];
		return true;
	}

	return false;
}

